package com.netty.rpc.server.factory;

import com.netty.rpc.server.annotation.Component;
import com.netty.rpc.server.annotation.ComponentScan;
import com.netty.rpc.server.config.AppConfig;
import com.netty.rpc.server.service.HelloService;
import lombok.extern.slf4j.Slf4j;

import java.io.File;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.*;

@Slf4j
public class DefaultServiceFactory extends ServiceFactory{

    private static ServiceFactory factory;
    private static Object LOCK=new Object();

    public DefaultServiceFactory(Class<?> configClass){
        this.scan(configClass);

    }



    @Override
    public <T> T getBean(Class<T> clazz) {
        String key=clazz.getSimpleName().substring(0,1).toLowerCase()+clazz.getSimpleName().substring(1);
        T bean = (T)this.cache.get(key);
        return bean;
    }

    public static ServiceFactory build(){
        if(factory==null){
            synchronized (LOCK){
                if(factory==null){
                    factory=new DefaultServiceFactory(AppConfig.class);
                }
            }
        }
        return factory;
    }

    private void scan(Class<?> componentClass) {
        ComponentScan componentClassDeclaredAnnotation = componentClass.getDeclaredAnnotation(ComponentScan.class);
        // 获取扫描路径
        String path = componentClassDeclaredAnnotation.value();
        log.info("当前扫描注册的路径为：{}",path);
        ClassLoader classLoader=this.getClass().getClassLoader();
        URI uri=null;
        try {
             uri= classLoader.getResource(path.replace(".", "/")).toURI();
        } catch (URISyntaxException e) {
            e.printStackTrace();
        }
        // 获取当前扫描包下的所有文件
        File file = new File(uri.getPath());
        // 定义文件队列
        Queue<File> fileQueue=new LinkedList<>();
        // 文件数组
        List<File> fileList=new ArrayList<>();
        fileQueue.add(file);
        // 获取文件数组
        this.getFiles(fileQueue,fileList);

        for (File targetFile : fileList) {
            // 获取加载类路径
            String filePath=targetFile.getAbsolutePath();
            if (!filePath.endsWith(".class")) continue;
            log.info("scan path --{}",filePath);
            String loadPath = filePath.substring(filePath.lastIndexOf("com"), filePath.lastIndexOf(".class")).replace("\\", ".");
            // 加载类
            Class clazz;
            try {
                clazz = classLoader.loadClass(loadPath);
                // 获取当前类是否有component注解
                if (clazz.isAnnotationPresent(Component.class)){
                    Component componentAnnotation = (Component) clazz.getDeclaredAnnotation(Component.class);
                    String beanName=componentAnnotation.value();
                    Class[] interfaces = clazz.getInterfaces();
                    if (interfaces.length>0){
                        beanName=interfaces[0].getSimpleName().substring(0,1).toLowerCase()+interfaces[0].getSimpleName().substring(1);
                    }else {
                        if (beanName.equals("")) beanName=clazz.getSimpleName().substring(0,1).toLowerCase()+clazz.getSimpleName().substring(1);
                    }
                    if (cache.containsKey(beanName)) throw new RuntimeException(beanName+" has been");
                    Object instance = clazz.newInstance();
                    cache.put(beanName,instance);
                }
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }

        }

    }

    private void getFiles(Queue<File> fileQueue, List<File> fileList) {
        while (!fileQueue.isEmpty()){
            File file = fileQueue.poll();
            if (file.isDirectory()){
                File[] files = file.listFiles();
                fileQueue.addAll(Arrays.asList(files));
            }else {
                fileList.add(file);
            }
        }
    }


}
